#ifndef SPI_H_
#define SPI_H_ true

#ifndef IAR
	#include <avr/io.h>
#endif

#include <stddef.h>
#include "Structs.h"
#include "Interface.h"
#include "Timer.h"

#define WaitMISO while (CheckPin(*Port.PinX, MISO)){};

enum SPI_RATE {R4, R16, R64, R128};

struct SPCRStruct{
	unsigned vSPR :2;
	unsigned vCPHA:1;
	unsigned vCPOL:1;
	unsigned vMSTR:1;
	unsigned vDORD:1;
	unsigned vSPE :1;
	unsigned vSPIE:1;
};

struct SPSRStruct{
	unsigned vSPIF:1;
	unsigned vWCOL:1;
	unsigned vNULL:5;
	unsigned vSPI2X:1;
};

class clSPIDevice;

class clSPI: public clInterface{
	public:
		clSPI(PortStruct Port, ePins lMISO, ePins lMOSI, ePins lSCK);
		void SelectDevice(const ePins CSPin);
		void UnSelectDevice(const ePins CSPin);
		virtual void SendData(clSPIDevice *lpDevice, unsigned char *Bytes, const unsigned char ByteCount);
		void Connect();
		void DisConnect();
	public:
		virtual void _SendData(clSPIDevice *lpDevice, unsigned char *Bytes, const unsigned char ByteCount);
		virtual void SendByte(clSPIDevice *lpDevice, unsigned char *Byte);
		PortStruct	Port;
		ePins		MISO;
		ePins		MOSI;
		ePins		SCK;
};

class clSPIProg: public clSPI{
	public:
		clSPIProg(PortStruct lPort, ePins lMISO, ePins lMOSI, ePins lSCK);
		void Connect();
		void DisConnect();
		void SendByte(clSPIDevice *lpDevice, unsigned char *Byte);
	protected:
//		virtual void SendByte(clSPIDevice *lpDevice, unsigned char *Byte);
		void SCKHoldUp(const clSPIDevice *lpDevice);
		void SCKHoldDown(const clSPIDevice *lpDevice);
		void SCKToDown(void);
};
class clSPIHWD;

class clSPIHDWDSignalSettings: public clMain{
	friend
		clSPIHWD;
	public:
		void DoubleSpeed(const bool Val);
		void CollisionFlag(const bool Val);
		void InteruptFlag(const bool Val);
		void ClockRate(const SPI_RATE Rate);
		void ClockPhase(const bool On);
		void ClockPolarity(const bool On);
		void CPUMaster(const bool On);
		void DataOrder(const bool On);
		void SPIEnable(const bool On);
		void SPIInterupt(const bool On);
	private:
		union{
			SPCRStruct		VAL;
			unsigned char	BYTE;
		} SPCRREG;

		union{
			SPSRStruct		VAL;
			unsigned char	BYTE;
		} SPSRREG;
};

class clSPIHWD: public clSPI{
	public:
		clSPIHWD(PortStruct lSPIPort, ePins lMISO, ePins lMOSI, ePins lSCK, ePins lCS);
		void Connect();
		void DisConnect();
		virtual void SendData(clSPIDevice *lpDevice, unsigned char *Bytes, unsigned char ByteCount);
		clSPIHDWDSignalSettings	SignalSettings;
	protected:
		virtual void SendByte(clSPIDevice *lpDevice, unsigned char *Byte);
		ePins CS;
};

class clSPIProgSignalSettings: public clMain{
	public:
		uint8_t	CSDurationUSx8;
};

class clSPISettings: public clMain{
	public:
		clSPISettings(void);
		clSPIProgSignalSettings SPIProgSignalSettings;
		ePins					CSPin;
		PortStruct				Port;
	
		bool				LowBitFirst;
		bool				WaitMISOSignal;
		bool				BurstSignal;
};


class clSPIDevice: public clMain{
	public:
		clSPIDevice(PortStruct Port);
		void Connect();
		void DisConnect();
		clSPISettings	SPISettings;
		clSPI *pSPI;
		bool GetState(void);
		void SetSPI(clSPI *lSPI);
		bool GetConnectStatus(void);
		void SendData(uint8_t *data, uint8_t length);
	protected:
		bool Connected;	
};

class clReg8WSPI:public clReg8{
	public:
		clSPIDevice	*pDevice;
		void SetValue(unsigned char lVal);
		void SendToSPI(void);
};

class clSPIDeviceWReg: public clSPIDevice{
	public:
		clSPIDeviceWReg(clSPI *lpSPI, PortStruct Port, ePins lCSPin);
		void Connect();
		void DisConnect();
	protected:
		void RegsSend(void);
};

#include "SPI.cpp"
#endif
